import { UnwrapRef, reactive, ref, toRefs } from 'vue'
import { BaseResponse } from '@/types/api'

export type UseRequestOptions<D> = {
	immediate?: boolean;
	showLoading?: boolean;
	showToast?: boolean;
	onError?: (e?: unknown) => void;
	onSuccess?: (data: D) => void;
}

export function useRequest<Data = any, Params extends any[] = []>(
	promise: Promise<BaseResponse<Data>> | ((...args: Params) => Promise<BaseResponse<Data>>),
	initialData: Data,
	options?: UseRequestOptions<Data>
) {
	const {
		immediate = true,
		showLoading = false,
		showToast = false,
		onError,
		onSuccess,
	} = options ?? {}

	const data = ref(initialData)
	const state = reactive({
		isReady: false,
		isLoading: false,
		isError: false,
	})

	let _showLoading = false

	const run = async (...args: any[]) => {
		state.isReady = false
		state.isLoading = true
		state.isError = false

		const _promise = typeof promise === 'function' ? promise(...args as Params) : promise

		try {
			if (showLoading && !_showLoading) {
				_showLoading = true
				uni.showLoading({
					mask: true,
				})
			}

			const response = await _promise

			if (showToast) {
				uni.showToast({
					title: response.msg,
					icon: 'none',
				})
			}

			if (response.code === 1) {
				data.value = response.data as UnwrapRef<Data>
				onSuccess?.(response.data)
			}
		} catch (e) {
			state.isError = true
			onError?.(e)
		} finally {
			state.isReady = true
			state.isLoading = false

			if (showLoading && _showLoading) {
				_showLoading = false
				uni.hideLoading()
			}
		}

		return data.value
	}

	if (immediate) run()

	return {
		data,
		...toRefs(state),
		run,
	}
}
